home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / opt / pinstaller / GLIClientController.py < prev    next >
Text File  |  2006-01-22  |  17KB  |  411 lines

  1. """
  2. # Copyright 1999-2005 Gentoo Foundation
  3. # This source code is distributed under the terms of version 2 of the GNU
  4. # General Public License as published by the Free Software Foundation, a copy
  5. # of which can be found in the main directory of this project.
  6. Gentoo Linux Installer
  7.  
  8. $Id: GLIClientController.py,v 1.76 2006/01/23 01:26:58 agaffney Exp $
  9. Copyright 2004 Gentoo Technologies Inc.
  10.  
  11. Steps (based on the ClientConfiguration):
  12.     1. Load any modules?  (this may have to be done manually, using a shell - not implemented)
  13.     2. Set the root password (may need to generate one. GLIUtility.generate_random_password())
  14.     3. Add users? (not implemented yet)
  15.     4. Start ssh
  16.     5. Network setup
  17.     6. Start the ArchTemplate doing it's thing. - maybe.. this might get called from elsewhere
  18.  
  19. """
  20.  
  21. import os, GLIClientConfiguration, GLIInstallProfile, GLIUtility, GLILogger, sys, signal, Queue, GLIArchitectureTemplate, GLINotification, traceback
  22. from GLIException import *
  23. from threading import Thread, Event
  24.  
  25. # Global constants for notifications
  26. NEXT_STEP_READY = 1
  27. INSTALL_DONE = 2
  28.  
  29. TEMPLATE_DIR = 'templates'
  30.  
  31. ##
  32. # This class provides an interface between the backend and frontend
  33. class GLIClientController(Thread):
  34.  
  35.     ##
  36.     # Initialization function for the GLIClientController class
  37.     # @param configuration=None GLIClientConfiguration object
  38.     # @param install_profile=None GLIInstallProfile object
  39.     # @param pretend=False Pretend mode. If pretending, no steps will actually be performed
  40.     def __init__(self,configuration=None,install_profile=None,pretend=False):
  41.         Thread.__init__(self)
  42.  
  43.         if configuration == None and os.path.isfile('/etc/gli.conf'):
  44.             self.output("Using /etc/gli.conf...")
  45.             configuration = GLIClientConfiguration.ClientConfiguration()
  46.             configuration.parse('/etc/gli.conf')
  47.  
  48.         self.set_install_profile(install_profile)
  49.         self.set_configuration(configuration)
  50.         self._install_event = Event()
  51.         self._notification_queue = Queue.Queue(50)
  52.         self._install_mode = None
  53.         self._install_step = -1
  54.         self._install_steps = None
  55.         self._pretend = pretend
  56.         self.setDaemon(True)
  57.  
  58.     ##
  59.     # Sets the GLIInstallProfile object
  60.     # @param install_profile GLIInstallProfile object
  61.     def set_install_profile(self, install_profile):
  62.         self._install_profile = install_profile
  63.  
  64.     ##
  65.     # Returns the GLIInstallProfile object
  66.     def get_install_profile(self):
  67.         return self._install_profile
  68.  
  69.     ##
  70.     # Sets the GLIClientConfiguration object
  71.     # @param configuration GLIClientConfiguration object
  72.     def set_configuration(self, configuration):
  73.         self._configuration = configuration
  74.         if self._configuration != None:
  75.             self._logger = GLILogger.Logger(self._configuration.get_log_file())
  76.  
  77.     ##
  78.     # Returns the GLIClientConfiguration object
  79.     def get_configuration(self):
  80.         return self._configuration
  81.  
  82.     ##
  83.     # This function runs as a second thread to do the actual installation (only used internally)
  84.     def run(self):
  85.         interactive = self._configuration.get_interactive()
  86.  
  87.         if self._configuration == None and not interactive and not self._pretend:
  88.             print "You can not do a non-interactive install without a ClientConfiguration!"
  89.             sys.exit(1)
  90.             
  91.         # Write client configuration profile to disk for debugging purposes
  92.         configuration = open("/tmp/clientconfiguration.xml", "w")
  93.         configuration.write(self._configuration.serialize())
  94.         configuration.close()
  95.  
  96.         steps = [self.load_kernel_modules, self.set_proxys, self.set_root_passwd, self.configure_networking, self.enable_ssh, self.start_portmap]
  97.         # Do Pre-install client-specific things here.
  98.         while len(steps) > 0:
  99.             try:
  100.                 step = steps.pop(0)
  101.                 if not self._pretend:
  102.                     step()
  103.             except GLIException, error:
  104.                 if error.get_error_level() != 'fatal':
  105.                     self._logger.log("Error: "+ error.get_function_name() + ": " + error.get_error_msg())
  106.                     self.output("Non-fatal error... continuing...")
  107.                 else:
  108.                     raise error
  109.         self._logger.log("Completed pre_install steps")
  110.  
  111.         # Wait for the self._install_event to be set before starting the installation.
  112.         # start_install() is called to pass here
  113.         self._install_event.wait()
  114.         self._install_event.clear()
  115.  
  116.         if self._install_profile == None and not interactive:    
  117.             print "You can not do a non-interactive install without an InstallProfile!"
  118.             sys.exit(1)
  119.  
  120.         #self.output("Starting install now...")
  121.  
  122.         templates = {    'x86':        'x86ArchitectureTemplate',
  123.                 'sparc':    'sparcArchitectureTemplate',
  124.                 'amd64':    'amd64ArchitectureTemplate',
  125.                 'mips':        'mipsArchitectureTemplate',
  126.                 'hppa':        'hppaArchitectureTemplate',
  127.                 'alpha':    'alphaArchitectureTemplate',
  128.                 'ppc':        'ppcArchitectureTemplate',
  129.                 'ppc64':    'ppc64ArchitectureTemplate'
  130.             }
  131.                 
  132.         if self._configuration.get_architecture_template() not in templates.keys():
  133.             self.addNotification("exception", GLIException("UnsupportedArchitectureError", "fatal", "run", self._configuration.get_architecture_template() + ' is not supported by the Gentoo Linux Installer!'))
  134.  
  135.         try:
  136.             template = __import__(TEMPLATE_DIR + '/' + templates[self._configuration.get_architecture_template()])
  137.             self._arch_template = getattr(template, templates[self._configuration.get_architecture_template()])(self._configuration, self._install_profile, self)
  138.         except ImportError:
  139.             self.addNotification("exception", GLIException("UnsupportedArchitectureError", 'fatal', 'run', 'The Gentoo Linux Installer could not import the install template for this architecture!'))
  140.         except AttributeError:
  141.             self.addNotification("exception", GLIException("UnsupportedArchitectureError", 'fatal', 'run', 'This architecture template was not defined properly!'))
  142.  
  143.         self._install_mode = self._configuration.get_install_mode()
  144.         tmp_install_steps = self._arch_template.get_install_steps()
  145.         self._install_steps = [step for step in tmp_install_steps if self._install_mode in step['modes']]
  146.  
  147.         if self._configuration.get_verbose(): self._logger.log("DEBUG: install_steps: " + str(self._install_steps))
  148.  
  149.         self.addNotification("int", NEXT_STEP_READY)
  150. #        self._install_event.wait()
  151.  
  152.         # Write install profile to disk for debugging purposes
  153.         configuration = open("/tmp/installprofile.xml", "w")
  154.         configuration.write(self._install_profile.serialize())
  155.         configuration.close()
  156.  
  157.         while 1:
  158.             if self._install_step >= len(self._install_steps): break
  159.             if self._configuration.get_verbose(): self._logger.log("DEBUG: waiting at top of 'while' loop in CC in secondary thread...waiting to start step " + str(self._install_step+1) + ", " + self._install_steps[(self._install_step+1)]['name'])
  160.             self._install_event.wait()
  161.             if self._configuration.get_verbose(): self._logger.log("DEBUG: Event() cleared at top of 'while' loop in CC in secondary thread...starting step " + str(self._install_step) + ", " + self._install_steps[(self._install_step)]['name'])
  162. #            if self._install_step <= (len(self._install_steps) - 1):
  163.             try:
  164.                 if not self._pretend:
  165.                     self._install_steps[self._install_step]['function']()
  166.                 self._install_event.clear()
  167.                 if self.has_more_steps():
  168.                     self.addNotification("int", NEXT_STEP_READY)
  169.                 else:
  170.                     self.addNotification("int", INSTALL_DONE)
  171.             except GLIException, error:
  172.                 etype, value, tb = sys.exc_info()
  173.                 s = traceback.format_exception(etype, value, tb)
  174.                 self._logger.log("Exception received during '" + self._install_steps[self._install_step]['name'] + "': " + str(error))
  175.                 for line in s:
  176.                     line = line.strip()
  177.                     self._logger.log(line)
  178.                 self.addNotification("exception", error)
  179.                 self._install_event.clear()
  180.             except Exception, error:
  181.                 # Something very bad happened
  182.                 etype, value, tb = sys.exc_info()
  183.                 s = traceback.format_exception(etype, value, tb)
  184.                 self._logger.log("This is a bad thing. An exception occured outside of the normal install errors. The error was: '" + str(error) + "'")
  185.                 for line in s:
  186.                     line = line.strip()
  187.                     self._logger.log(line)
  188.                 self.addNotification("exception", error)
  189.                 self._install_event.clear()
  190. #            else:
  191. #                break
  192.  
  193.         # This keeps the thread running until the FE exits
  194.         self._install_event.clear()
  195.         self._install_event.wait()
  196.  
  197.     ##
  198.     # Returns the number of steps in the install process
  199.     def get_num_steps(self):
  200.         return len(self._install_steps)
  201.  
  202.     ##
  203.     # Returns information about the next install step
  204.     def get_next_step_info(self):
  205.         return self._install_steps[(self._install_step + 1)]['name']
  206.  
  207.     ##
  208.     # Performs the next install step
  209.     def next_step(self):
  210.         self._install_step = self._install_step + 1
  211.         if self._configuration.get_verbose(): self._logger.log("DEBUG: next_step(): setting Event() flag...starting step " + str(self._install_step) + ", " + self._install_steps[(self._install_step)]['name'])
  212.         self._install_event.set()
  213.  
  214.     ##
  215.     # Retries the current install step
  216.     def retry_step(self):
  217.         self._install_event.set()
  218.  
  219.     ##
  220.     # Returns True if there are more install steps remaining
  221.     def has_more_steps(self):
  222.         return (self._install_step < (len(self._install_steps) - 1))
  223.  
  224.     ##
  225.     # Sets proxy information from the environment
  226.     def set_proxys(self):
  227.         if self._configuration.get_verbose(): self._logger.log("DEBUG: beginning of set_proxys()")
  228.         if self._configuration.get_ftp_proxy() != "":
  229.             os.environ['ftp_proxy'] = self._configuration.get_ftp_proxy()
  230.  
  231.         if self._configuration.get_http_proxy() != "":
  232.             os.environ['http_proxy'] = self._configuration.get_http_proxy()
  233.  
  234.         if self._configuration.get_rsync_proxy() != "":
  235.             os.environ['RSYNC_PROXY'] = self._configuration.get_rsync_proxy()
  236.         if self._configuration.get_verbose(): self._logger.log("DEBUG: end of set_proxys()")
  237.  
  238.     ##
  239.     # Loads kernel modules specified in the GLIClientConfiguration object
  240.     def load_kernel_modules(self):
  241.         if self._configuration.get_verbose(): self._logger.log("DEBUG: beginning of load_kernel_modules()")
  242.         modules = self._configuration.get_kernel_modules()
  243.         if self._configuration.get_verbose(): self._logger.log("DEBUG: load_kernel_modules(): modules are " + str(modules))
  244.         for module in modules:
  245.             try:
  246.                 if self._configuration.get_verbose(): self._logger.log("DEBUG: load_kernel_modules(): trying to load module " + module)
  247.                 ret = GLIUtility.spawn('modprobe ' + module)
  248.                 if not GLIUtility.exitsuccess(ret):
  249.                     self._logger.log("ERROR! : Could not load module: "+module)
  250.                 #    raise GLIException("KernelModuleError", 'warning', 'load_kernel_modules', 'Could not load module: ' + module)
  251.                 else:
  252.                     self._logger.log('kernel module: ' + module + ' loaded.')
  253.             except KernelModuleError, error:
  254.                 self.output(error)
  255.                 self._logger.log(error.get_error_level() + '! ' + error.get_error_msg())
  256.  
  257.     ##
  258.     # Sets the root password specified in the GLIClientConfiguration object
  259.     def set_root_passwd(self):
  260.         self._logger.log("Setting root password.")
  261.         if self._configuration.get_root_passwd() != "":
  262.             # The password specified in the configuration is encrypted.
  263.             status = GLIUtility.spawn("echo 'root:" + self._configuration.get_root_passwd() + "' | chpasswd -e")
  264.     
  265.             if not GLIUtility.exitsuccess(status):
  266.                 self._logger.log("ERROR! : Could not set the root password on the livecd environment!")
  267.             #    raise GLIException("PasswordError", 'warning', 'set_root_passwd', "Could not set the root password!")
  268.             else:
  269.                 self._logger.log("Livecd root password set.")
  270.  
  271.     ##
  272.     # Starts portmap if specified in the GLIClientConfiguration object
  273.     def start_portmap(self):
  274.         if self._configuration.get_verbose(): self._logger.log("DEBUG: beginning of start_portmap()")
  275.         status = GLIUtility.spawn('/etc/init.d/portmap start') #, display_on_tty8=True)
  276.         if not GLIUtility.exitsuccess(status):
  277.             self._logger.log("ERROR! : Could not start the portmap service!")
  278.         #    raise GLIException("PortmapError", 'warning', 'start_portmap', "Could not start the portmap service!")
  279.         else:
  280.             self._logger.log("Portmap started.")
  281.  
  282.     ##
  283.     # Configures networking as specified in the GLIClientConfiguration object
  284.     def configure_networking(self):
  285.         if self._configuration.get_verbose(): self._logger.log("DEBUG: beginning of configure_networking()")
  286.         # Do networking setup right here.
  287.         if self._configuration.get_network_type() != None:
  288.             type = self._configuration.get_network_type()
  289.             if type == "null":
  290.                 # don't do anything, it's not our problem if the user specifies this.
  291.                 return
  292.             if type == "dhcp":
  293.                 if self._configuration.get_verbose(): self._logger.log("DEBUG: configure_networking(): DHCP selected")
  294.                 # Run dhcpcd.
  295.                 try:
  296.                     interface = self._configuration.get_network_interface()
  297.                     dhcp_options = self._configuration.get_network_dhcp_options()
  298.                 except:
  299.                     self._logger.log("No interface found.. defaulting to eth0.")
  300.                     interface = "eth0"
  301.                     dhcp_options = ""
  302.  
  303.                 if interface and not dhcp_options:
  304.                     if self._configuration.get_verbose(): self._logger.log("DEBUG: configure_networking(): running '/sbin/dhcpcd -n " + interface + "'")
  305.                     status = GLIUtility.spawn("/sbin/dhcpcd -n " + interface)
  306.                 elif interface and dhcp_options:
  307.                     if self._configuration.get_verbose(): self._logger.log("DEBUG: configure_networking(): running '/sbin/dhcpcd " + dhcp_options + " " + interface + "'")
  308.                     status = GLIUtility.spawn("/sbin/dhcpcd " + dhcp_options + " " + interface)
  309.                 else:
  310.                     if self._configuration.get_verbose(): self._logger.log("DEBUG: configure_networking(): running '/sbin/dhcpcd -n'")
  311.                     status = GLIUtility.spawn("/sbin/dhcpcd -n")
  312.                 if self._configuration.get_verbose(): self._logger.log("DEBUG: configure_networking(): call to /sbin/dhcpcd complete")
  313.  
  314.                 if not GLIUtility.exitsuccess(status):
  315.                     raise GLIException("DHCPError", 'fatal', 'configure_networking', "Failed to get a dhcp address for " + interface + ".")
  316.  
  317.             elif type == "manual" and self._configuration.get_interactive():
  318.                 # Drop to bash shell and let them configure it themselves
  319.                 print "Please configure & test your network device."
  320.                 GLIUtility.spawn_bash()
  321.             elif type == "manual" and not self._interactive.get_interactive():
  322.                 print "You cannot manually configure the network in non-interactive mode!"
  323.                 print "Please fix either the network settings or the interactive mode!"
  324.                 sys.exit(1)
  325.             elif type == "static":
  326.                 if self._configuration.get_verbose(): self._logger.log("DEBUG: configure_networking(): setting static IP")
  327.                 # Configure the network from the settings they gave.
  328.                 net_interface = self._configuration.get_network_interface()
  329.                 net_ip        = self._configuration.get_network_ip()
  330.                 net_broadcast = self._configuration.get_network_broadcast()
  331.                 net_netmask   = self._configuration.get_network_netmask()
  332.                 if not GLIUtility.set_ip(net_interface, net_ip, net_broadcast, net_netmask):
  333.                     raise GLIException("SetIPError", 'fatal', 'configure_networking', "Could not set the IP address!")
  334.  
  335.                 route = self._configuration.get_network_gateway()
  336.                 if not GLIUtility.set_default_route(route):
  337.                     raise GLIException("DefaultRouteError", 'fatal','configure_networking', "Could not set the default route!")
  338.                 if self._configuration.get_verbose(): self._logger.log("DEBUG: configure_networking(): done setting static IP")
  339.  
  340.     ##
  341.     # Enables SSH if specified in the GLIClientConfiguration object
  342.     def enable_ssh(self):
  343.         if self._configuration.get_verbose(): self._logger.log("DEBUG: beginning of enable_ssh()")
  344.         if self._configuration.get_enable_ssh():
  345.             status = GLIUtility.spawn("/etc/init.d/sshd start")
  346.             if not GLIUtility.exitsuccess(status):
  347.                 self._logger.log("ERROR! : Could not start the SSH daemon!")
  348.             #    raise GLIException("SSHError", 'warning','enable_ssh',"Could not start SSH daemon!")
  349.             else:
  350.                 self._logger.log("SSH Started.")
  351.  
  352.     ##
  353.     # Loads the install profile
  354.     def load_install_profile(self):
  355.         install_profile=None
  356.         if self._install_profile == None:
  357.             if self._configuration != None:
  358.                 success = GLIUtility.get_uri(self._configuration.get_profile_uri(),'/tmp/install_profile.xml')
  359.                 if success:
  360.                     self._logger.log("Profile downloaded succesfully, loading it now.")
  361.                     self.output("Profile downloaded... loading it now...")
  362.                     install_profile = GLIInstallProfile.InstallProfile()
  363.                     install_profile.parse('/tmp/install_profile.xml')
  364.                 else:
  365.                     raise GLIException("InstallProfileError", 'fatal', 'get_install_profile', 'Could not download/copy the install profile from: ' + self._configuration.get_profile_uri())
  366.  
  367.         self._install_profile = install_profile
  368.  
  369.     ##
  370.     # Starts the install
  371.     def start_install(self):
  372.         self._install_event.set()
  373.  
  374.     ##
  375.     # Starts the secondary thread running. The thread will wait to continue until start_install() is called
  376.     def start_pre_install(self):
  377.         self.start()
  378.  
  379.     ##
  380.     # Cleans up after a failed install
  381.     def start_failure_cleanup(self):
  382.         self._arch_template.install_failed_cleanup()
  383.  
  384.     ##
  385.     # Displays specified output
  386.     # @param str String to display
  387.     def output(self, str):
  388.         print str
  389.  
  390.     ##
  391.     # Returns a notification object from the queue
  392.     def getNotification(self):
  393.         notification = None
  394.         try:
  395.             notification = self._notification_queue.get_nowait()
  396.         except:
  397.             pass
  398.         return notification
  399.  
  400.     ##
  401.     # Adds a notification object to the queue
  402.     # @param type Notification type
  403.     # @param data Notification contents
  404.     def addNotification(self, type, data):
  405.         notification = GLINotification.GLINotification(type, data)
  406.         try:
  407.             self._notification_queue.put_nowait(notification)
  408.         except:
  409.             # This should only ever happen if the frontend is not checking for notifications
  410.             pass
  411.